import subprocess
import time
import re
import os
from uiautomator2 import UiObjectNotFoundError
from wda import WDAElementNotFoundError

from common.app_info import GlobalVar, PhoneBy
from common.driver import MyDriver
from common.error import NotSupportLocatorTypeErr
from utils.PathUtil import SCREEN_SHOT_PATH
from utils.time_utils import YMDHMS__


screenshot_path = lambda p: os.path.abspath(os.path.join(os.path.dirname(__file__), p))


class ATXBase(MyDriver):

    def __init__(self, app_plat, app_tag):
        """
        app_system: ios 或安卓
        app_tag：云智连 or 智慧生活 or 微信
        """
        self.platform = app_plat
        self.app_name = app_tag
        if self.platform == GlobalVar.IOS:
            self.driver, self.app_package = self.init_ios_driver(self.app_name)
            print(f"启动iOS测试APP")
        else:
            self.driver, self.app_package = self.init_android_driver(app_tag=self.app_name)
            print(f"启动Android测试APP")

    def sleep_op(self, seconds: float, msg=''):
        if self.platform == GlobalVar.IOS:
            print(f"{msg}在此等待{seconds}秒")
            self.driver.sleep(secs=seconds)
        else:
            print(f"{msg}在此等待{seconds}秒")
            self.driver.sleep(seconds=seconds)

    def stop_app(self):
        print(f"关闭测试App: {self.app_package}")
        self.driver.app_stop(self.app_package)

    def start_setting(self):
        """
        打开设置
        :return:
        """
        if self.platform == GlobalVar.IOS:
            self.driver.app_start("com.apple.Preferences")
        else:
            self.driver.app_start("com.android.settings")

    def stop_setting(self):
        """
        关闭设置
        :return:
        """
        if self.platform == GlobalVar.IOS:
            self.driver.app_stop("com.apple.Preferences")
        else:
            self.click_home()
            self.driver.app_stop("com.android.settings")

    def click_home(self):
        """
        home button
        :return:
        """
        self.driver.press("home")

    def tap_screen(self, x_pct, y_pct, percentage=True):
        """
        x_pct: x 轴的百分比
        y_pct： y 轴的百分比
        :return:
        """
        if percentage:
            phone_size = self.driver.window_size()
            width = phone_size[0]
            height = phone_size[1]
            if self.platform == GlobalVar.IOS:
                self.driver.tap(int(width * x_pct), int(height * y_pct))
            else:
                self.driver.click(int(width * x_pct), int(height * y_pct))
        else:
            if self.platform == GlobalVar.IOS:
                self.driver.tap(x_pct, y_pct)
            else:
                self.driver.click(x_pct, y_pct)

    def every_step_screenshot(self, picture_title="", wait_time=0.5):
        save_picture = GlobalVar.PICTURE_PATH
        if save_picture is not None:
            pic_index = GlobalVar.PICTURE_NUM
            GlobalVar.picture_number(pic_index + 1)

            screen_image_name = os.path.join(save_picture, f"{picture_title}_{GlobalVar.PICTURE_NUM}.png")
            time.sleep(wait_time)
            self.driver.screenshot().save(screen_image_name)
        else:
            pass

    def alert_watcher_ios(self, watcher_info: list, watcher_countdown=6, wait_time=1):
        """
        watcher_countdown: 函数监控倒计时
        watcher_info: ios就是list  ["忽略该设备", "确定"]
                    安卓就是元组的 元素  (PhoneBy.AccessibilityId, '忽略该设备')
        """
        print(f"忽略配网设备弹框，监控{watcher_countdown}秒")
        start_watch = time.time()
        while time.time() - start_watch <= watcher_countdown:
            if self.driver.alert.wait(wait_time):  # wait_time 秒内弹框没有出现，就返回False
                self.driver.alert.click(watcher_info)

    def get_current_app(self):
        return self.driver.app_current()


    def alert_watcher_android(self, locator, watcher_countdown=6, wait_time=1):
        """
        watcher_countdown: 函数监控倒计时
        watcher_info: ios就是list  ["忽略该设备", "确定"]
                    安卓就是元组的 元素  (PhoneBy.AccessibilityId, '忽略该设备')
        """
        print(f"忽略配网设备弹框，监控{watcher_countdown}秒")
        android_st_time = time.time()
        while time.time() - android_st_time <= watcher_countdown:
            find_ignore_device = self.find_element(locator=locator, timeout=wait_time)
            if find_ignore_device is not None:
                find_ignore_device.click()

    @staticmethod
    def replace_custom_locate_xpath_element(locate_: tuple, replaced: str | None) -> tuple:
        """
        对元素中需要替换的自定义value 进行处理
        暂定自定义替换 value $$$ - 真实值
        3​6​0​可​视​门​铃​6​t​e​s​t
        """
        locate_value = locate_[1]
        if "$$$" in locate_value:
            if replaced is None:
                print(f"存在替换value，但没有可替换值，请确认元素{locate_value}")
                return locate_
            else:
                # 为啥有奇怪的符号 3​6​0​可​视​门​铃​6​t​e​s​t
                fff = '​'.join([rp for rp in replaced])
                value1 = locate_value.replace("$$$", replaced)
                value2 = locate_value.replace("$$$", fff)
                final_replace = (PhoneBy.XPATH, [value1, value2])
                return final_replace
        else:
            return locate_

    """
    此项目我只支持 ios和安卓都有的定位方式，其他的没必要支持。如下
    ios:          id     text  className    label          labelContains   xpath
    wda获取所有元素 u(id="id").find_elements()
    
    android:  resourceId text  className   description descriptionContains xpath (u2不建议使用，速度不快)
    u2默认返回所有的元素
    """

    def find_element_by_id(self, element_id, timeout, iosAll=False, androidAll=False):
        if self.platform == GlobalVar.IOS:
            try:
                if iosAll:
                    id_ele_ios = self.driver(id=element_id).find_elements()
                    if id_ele_ios:
                        return id_ele_ios
                    # 找不到返回 []
                    return None
                return self.driver(id=element_id).get(timeout=timeout)
            except WDAElementNotFoundError as we:
                print(f"控件【{element_id}】超时没找到")
                return None
        else:
            try:
                if androidAll:
                    if self.driver(resourceId=element_id).exists(timeout=timeout):
                        return self.driver(resourceId=element_id)
                    return None
                else:
                    if self.driver(resourceId=element_id).exists(timeout=timeout):
                        return self.driver(resourceId=element_id)[0]
                    return None
            except UiObjectNotFoundError as ue:
                print(f"控件【{element_id}】超时没找到")
                return None

    def id_element_clickable(self, element_id, timeout):
        if self.platform == GlobalVar.IOS:
            if self.driver(id=element_id).click_exists(timeout=timeout):
                return True
            return False

        else:
            try:
                if self.driver(resourceId=element_id).exists(timeout=timeout):
                    self.driver(resourceId=element_id)[0].click()
                    return True
                return False
            except UiObjectNotFoundError as ue:
                return False

    def id_element_exists(self, element_id, timeout):
        if self.platform == GlobalVar.IOS:
            if self.driver(id=element_id).wait(timeout=timeout) is not None:
                return True
            return False
        else:
            if self.driver(resourceId=element_id).exists(timeout=timeout):
                return True
            return False

    def id_element_not_exists(self, element_id, timeout):
        if self.platform == GlobalVar.IOS:
            if self.driver(id=element_id).wait_gone(timeout=timeout, raise_error=False):
                return True
            return False
        else:
            if self.driver(resourceId=element_id).wait_gone(timeout=timeout):
                return True
            return False

    def find_element_by_class_name(self, element_class_name, timeout, iosAll=False, androidAll=False):
        if self.platform == GlobalVar.IOS:
            try:
                if iosAll:
                    id_ele_ios = self.driver(className=element_class_name).find_elements()
                    if id_ele_ios:
                        return id_ele_ios
                    # 找不到返回 []
                    return None
                return self.driver(className=element_class_name).get(timeout=timeout)
            except WDAElementNotFoundError as we:
                print(f"控件【{element_class_name}】超时没找到")
                return None
        else:
            try:
                if androidAll:
                    if self.driver(className=element_class_name).exists(timeout=timeout):
                        return self.driver(className=element_class_name)
                    return None
                else:
                    if self.driver(className=element_class_name).exists(timeout=timeout):
                        return self.driver(className=element_class_name)[0]
                    return None
            except UiObjectNotFoundError as ue:
                print(f"控件【{element_class_name}】超时没找到")
                return None

    def class_name_element_clickable(self, element_class_name, timeout):
        if self.platform == GlobalVar.IOS:
            if self.driver(className=element_class_name).click_exists(timeout=timeout):
                return True
            return False

        else:
            try:
                if self.driver(className=element_class_name).exists(timeout=timeout):
                    self.driver(className=element_class_name)[0].click()
                    return True
                return False
            except UiObjectNotFoundError as ue:
                return False

    def class_name_element_exists(self, element_class_name, timeout):
        if self.platform == GlobalVar.IOS:
            if self.driver(className=element_class_name).wait(timeout=timeout) is not None:
                return True
            return False
        else:
            if self.driver(className=element_class_name).exists(timeout=timeout):
                return True
            return False

    def class_name_element_not_exists(self, element_class_name, timeout):
        if self.platform == GlobalVar.IOS:
            if self.driver(className=element_class_name).wait_gone(timeout=timeout, raise_error=False):
                return True
            return False
        else:
            if self.driver(className=element_class_name).wait_gone(timeout=timeout):
                return True
            return False

    def find_element_by_xpath(self, element_xpath, timeout, iosAll=False, androidAll=False):
        """
        根据xpath查找控件. 扩展的功能，速度慢，尽量不使用
        """
        if self.platform == GlobalVar.IOS:
            try:
                if iosAll:
                    xpath_ele_ios = self.driver(xpath=element_xpath).find_elements()
                    if xpath_ele_ios:
                        return xpath_ele_ios
                    # 找不到返回 []
                    return None
                return self.driver(xpath=element_xpath).get(timeout=timeout)
            except WDAElementNotFoundError as we:
                print(f"控件【{element_xpath}】超时没找到")
                return None
        else:
            try:
                if androidAll:
                    xpath_ele = self.driver.xpath(element_xpath).all()
                    if xpath_ele:
                        return xpath_ele
                    return None
                else:
                    if self.driver.xpath(element_xpath).wait(timeout=timeout):
                        return self.driver.xpath(element_xpath)
                    return None
            except UiObjectNotFoundError as ue:
                print(f"控件【{element_xpath}】超时没找到")
                return None

    def xpath_element_clickable(self, element_xpath, timeout):
        if self.platform == GlobalVar.IOS:
            if self.driver(xpath=element_xpath).click_exists(timeout=timeout):
                return True
            return False
        else:
            try:
                if self.driver.xpath(element_xpath).wait(timeout=timeout):
                    self.driver.xpath(element_xpath).click()
                    return True
                return False
            except UiObjectNotFoundError as ue:
                return False

    def xpath_element_exists(self, element_xpath, timeout):
        """
        根据xpath查找控件. 扩展的功能，速度慢，尽量不使用
        """
        if self.platform == GlobalVar.IOS:
            if self.driver(xpath=element_xpath).wait(timeout=timeout) is not None:
                return True
            return False
        else:
            if self.driver.xpath(element_xpath).wait(timeout=timeout):
                return True
            return False

    def xpath_element_not_exists(self, element_xpath, timeout=5):
        if self.platform == GlobalVar.IOS:
            if self.driver(xpath=element_xpath).wait_gone(timeout=timeout, raise_error=False):
                return True
            return False
        else:
            if self.driver.xpath(element_xpath).wait_gone(timeout=timeout):
                return True
            return False

    def find_similar_accessibility_id(self, element_id, isContains=False, timeout=0.1, iosAll=False, androidAll=False):
        """
        支持多个元素遍历查询
        :param androidAll: android所有元素
        :param iosAll  ios所有元素
        :param element_id: Android description 相当于appium 的 accessibility id
                           ios的 label 相当于 appium 的 accessibility id
        :param timeout  ios的超时
        :param isContains: 如果是True 就执行包含的元素查找
        :return: 控件对象
        """
        if self.platform == GlobalVar.IOS:
            try:
                if iosAll:
                    if isContains:
                        labelContain_ele_ios = self.driver(labelContains=element_id).find_elements()
                        if labelContain_ele_ios:
                            return labelContain_ele_ios
                        # 找不到返回 []
                        return None
                    else:
                        label_ele_ios = self.driver(label=element_id).find_elements()
                        if label_ele_ios:
                            return label_ele_ios
                        # 找不到返回 []
                        return None
                else:
                    if isContains:
                        return self.driver(labelContains=element_id).get(timeout=timeout)
                    return self.driver(label=element_id).get(timeout=timeout)
            except WDAElementNotFoundError as we:
                print(f"控件【{element_id}】超时没找到")
                return None
        else:
            try:
                if androidAll:
                    if isContains:
                        if self.driver(descriptionContains=element_id).exists(timeout=timeout):
                            return self.driver(descriptionContains=element_id)
                        return None
                    else:
                        if self.driver(description=element_id).exists(timeout=timeout):
                            return self.driver(description=element_id)
                        return None
                else:
                    if isContains:
                        if self.driver(descriptionContains=element_id).exists(timeout=timeout):
                            return self.driver(descriptionContains=element_id)[0]
                        return None
                    else:
                        if self.driver(description=element_id).exists(timeout=timeout):
                            return self.driver(description=element_id)[0]
                        return None
            except UiObjectNotFoundError as ue:
                print(f"控件【{element_id}】超时没找到")
                return None

    def accessibility_id_element_clickable(self, element_id, isContains=False, timeout=0.5):
        if self.platform == GlobalVar.IOS:
            if isContains:
                if self.driver(labelContains=element_id).click_exists(timeout=timeout):
                    return True
                return False
            else:
                if self.driver(label=element_id).click_exists(timeout=timeout):
                    return True
                return False
        else:
            try:
                if isContains:
                    if self.driver(descriptionContains=element_id).exists(timeout=timeout):
                        description_ele = self.driver(descriptionContains=element_id)[0]
                        description_ele.click()
                        return True
                    return False
                else:
                    if self.driver(description=element_id).exists(timeout=timeout):
                        description_ele = self.driver(description=element_id)[0]
                        description_ele.click()
                        return True
                    return False
            except UiObjectNotFoundError as ue:
                return False

    def accessibility_id_element_exists(self, element_id, isContains=False, timeout=0.1):
        if self.platform == GlobalVar.IOS:
            if isContains:
                if self.driver(labelContains=element_id).wait(timeout=timeout) is not None:
                    return True
                return False
            else:
                if self.driver(label=element_id).wait(timeout=timeout) is not None:
                    return True
                return False
        else:
            if isContains:
                if self.driver(descriptionContains=element_id).exists(timeout=timeout):
                    return True
                return False
            else:
                if self.driver(description=element_id).exists(timeout=timeout):
                    return True
                return False

    def accessibility_id_element_not_exists(self, element_id, isContains=False, timeout=0.1):
        if self.platform == GlobalVar.IOS:
            if isContains:
                if self.driver(labelContains=element_id).wait_gone(timeout=timeout, raise_error=False):
                    return True
                return False
            else:
                if self.driver(label=element_id).wait_gone(timeout=timeout, raise_error=False):
                    return True
                return False
        else:
            if isContains:
                if self.driver(descriptionContains=element_id).wait_gone(timeout=timeout):
                    return True
                return False
            else:
                if self.driver(description=element_id).wait_gone(timeout=timeout):
                    return True
                return False

    def find_element_by_class_name_text(self, class_name, text, isContains=False, timeout=0.5, iosAll=False,
                                        androidAll=False):
        """
        组合定位
        """
        if self.platform == GlobalVar.IOS:
            try:
                if iosAll:
                    if isContains:
                        class_name_text_ele_contain = self.driver(className=class_name,
                                                                  textContains=text).find_elements()
                        if class_name_text_ele_contain:
                            return class_name_text_ele_contain
                        return None
                    else:
                        class_name_text_ele = self.driver(className=class_name, text=text).find_elements()
                        if class_name_text_ele:
                            return class_name_text_ele
                        return None
                else:
                    if isContains:
                        return self.driver(className=class_name, textContains=text).get(timeout=timeout)
                    else:
                        return self.driver(className=class_name, text=text).get(timeout=timeout)
            except WDAElementNotFoundError as we:
                print(f"控件【{class_name}】【{text}】超时没找到")
                return None
        else:
            try:
                if androidAll:
                    if isContains:
                        if self.driver(className=class_name, textContains=text).exists(timeout=timeout):
                            return self.driver(className=class_name, textContains=text)
                        return None
                    else:
                        if self.driver(className=class_name, text=text).exists(timeout=timeout):
                            return self.driver(className=class_name, text=text)
                        return None
                else:
                    if isContains:
                        if self.driver(className=class_name, textContains=text).exists(timeout=timeout):
                            return self.driver(className=class_name, textContains=text)[0]
                        return None
                    else:
                        if self.driver(className=class_name, text=text).exists(timeout=timeout):
                            return self.driver(className=class_name, text=text)[0]
                        return None
            except UiObjectNotFoundError as ue:
                print(f"控件【{class_name}】【{text}】超时没找到")
                return None

    def class_name_text_element_clickable(self, class_name, text, isContains=False, timeout=0.5):
        """
        组合定位
        """
        if self.platform == GlobalVar.IOS:
            if isContains:
                if self.driver(className=class_name, textContains=text).click_exists(timeout=timeout):
                    return True
                return False
            else:
                if self.driver(className=class_name, text=text).click_exists(timeout=timeout):
                    return True
                return False
        else:
            try:
                if isContains:
                    if self.driver(className=class_name, textContains=text).exists(timeout=timeout):
                        self.driver(className=class_name, textContains=text)[0].click()
                        return True
                    return False
                else:
                    if self.driver(className=class_name, text=text).exists(timeout=timeout):
                        self.driver(className=class_name, text=text)[0].click()
                        return True
                    return False
            except UiObjectNotFoundError as ue:
                return False

    def class_name_text_element_exists(self, class_name, text, isContains=False, timeout=0.5):
        """
        组合定位
        """
        if self.platform == GlobalVar.IOS:
            if isContains:
                if self.driver(className=class_name, textContains=text).wait(timeout=timeout) is not None:
                    return True
                return False
            else:
                if self.driver(className=class_name, text=text).wait(timeout=timeout) is not None:
                    return True
                return False
        else:
            if isContains:
                if self.driver(className=class_name, textContains=text).exists(timeout=timeout):
                    return True
                return False
            else:
                if self.driver(className=class_name, text=text).exists(timeout=timeout):
                    return True
                return False

    def class_name_text_element_not_exists(self, class_name, text, isContains=False, timeout=5):
        """
        组合定位
        """
        if self.platform == GlobalVar.IOS:
            if isContains:
                if self.driver(className=class_name, textContains=text).wait_gone(timeout=timeout, raise_error=False):
                    return True
                return False
            else:
                if self.driver(className=class_name, text=text).wait_gone(timeout=timeout, raise_error=False):
                    return True
                return False
        else:
            if isContains:
                if self.driver(className=class_name, textContains=text).wait_gone(timeout=timeout):
                    return True
                return False
            else:
                if self.driver(className=class_name, text=text).wait_gone(timeout=timeout):
                    return True
                return False

    def find_element(self, locator, isContains=False, timeout=8.0):
        """
        每种元素都支持 多元素查找
        :param locator: 元组：(定位方法, 定位文本)，比如('xpath', '//*[@text="视频"]')
                        list: 每种元素支持 多种方式查找
                        结构如下：[(PhoneBy.ID,["id1","id2"]),(PhoneBy.XPATH,["path1","path2"])]

        :param isContains
        :param timeout: ios 超时
        :return:
        """
        if isinstance(locator, list):
            for lo in locator:
                method = lo[0]
                values = lo[1]
                if method == PhoneBy.ID:
                    if isinstance(values, list):
                        start_time = time.time()
                        while time.time() - start_time <= timeout:
                            for va in values:
                                get_va = self.find_element_by_id(va, 0.1, False, False)
                                if get_va is not None:
                                    return get_va
                                continue
                    else:
                        get_va = self.find_element_by_id(values, timeout, False, False)
                        if get_va is not None:
                            return get_va

                elif method == PhoneBy.XPATH:
                    if isinstance(values, list):
                        start_time = time.time()
                        while time.time() - start_time <= timeout:
                            for va in values:
                                get_va = self.find_element_by_xpath(va, 0.1, False, False)
                                if get_va is not None:
                                    return get_va
                                continue
                    else:
                        get_va = self.find_element_by_xpath(values, timeout, False, False)
                        if get_va is not None:
                            return get_va

                elif method == PhoneBy.AccessibilityId:
                    if isinstance(values, list):
                        start_time = time.time()
                        while time.time() - start_time <= timeout:
                            for va in values:
                                get_va = self.find_similar_accessibility_id(va, isContains, 0.1, False, False)
                                if get_va is not None:
                                    return get_va
                                continue
                    else:
                        get_va = self.find_similar_accessibility_id(values, isContains, timeout, False, False)
                        if get_va is not None:
                            return get_va

                elif method == PhoneBy.COMPOSE_CLASS_NAME_WITH_TEXT:
                    # class_name, text
                    if isinstance(values, list):
                        start_time = time.time()
                        while time.time() - start_time <= timeout:
                            for va in values:
                                get_va = self.find_element_by_class_name_text(va[0], va[1], isContains, 0.1,
                                                                              False, False)
                                if get_va is not None:
                                    return get_va
                                continue
                    else:
                        get_va = self.find_element_by_class_name_text(values[0], values[1], isContains, timeout,
                                                                      False, False)
                        if get_va is not None:
                            return get_va

                elif method == PhoneBy.CLASS_NAME:
                    if isinstance(values, list):
                        start_time = time.time()
                        while time.time() - start_time <= timeout:
                            for va in values:
                                get_va = self.find_element_by_class_name(va, 0.1, False, False)
                                if get_va is not None:
                                    return get_va
                                continue
                    else:
                        get_va = self.find_element_by_class_name(values, timeout, False, False)
                        if get_va is not None:
                            return get_va

                continue
            return None
        else:
            method = locator[0]
            values = locator[1]
            if method == PhoneBy.ID:
                if isinstance(values, list):
                    start_time = time.time()
                    while time.time() - start_time <= timeout:
                        for va in values:
                            get_va = self.find_element_by_id(va, 0.1, False, False)
                            if get_va is not None:
                                return get_va
                            continue
                    return None
                else:
                    return self.find_element_by_id(values, timeout, False, False)

            elif method == PhoneBy.XPATH:
                if isinstance(values, list):
                    start_time = time.time()
                    while time.time() - start_time <= timeout:
                        for va in values:
                            get_va = self.find_element_by_xpath(va, 0.1, False, False)
                            if get_va is not None:
                                return get_va
                            continue
                    return None
                else:
                    return self.find_element_by_xpath(values, timeout, False, False)

            elif method == PhoneBy.AccessibilityId:
                if isinstance(values, list):
                    start_time = time.time()
                    while time.time() - start_time <= timeout:
                        for va in values:
                            get_va = self.find_similar_accessibility_id(va, isContains, 0.1, False, False)
                            if get_va is not None:
                                return get_va
                            continue
                    return None
                else:
                    return self.find_similar_accessibility_id(values, isContains, timeout, False, False)

            elif method == PhoneBy.COMPOSE_CLASS_NAME_WITH_TEXT:
                # class_name, text
                if isinstance(values, list):
                    start_time = time.time()
                    while time.time() - start_time <= timeout:
                        for va in values:
                            get_va = self.find_element_by_class_name_text(va[0], va[1], isContains, 0.1, False, False)
                            if get_va is not None:
                                return get_va
                            continue
                    return None
                else:
                    return self.find_element_by_class_name_text(values[0], values[1], isContains, timeout, False, False)

            elif method == PhoneBy.CLASS_NAME:
                if isinstance(values, list):
                    start_time = time.time()
                    while time.time() - start_time <= timeout:
                        for va in values:
                            get_va = self.find_element_by_class_name(va, 0.1, False, False)
                            if get_va is not None:
                                return get_va
                            continue
                    return None
                else:
                    return self.find_element_by_class_name(values, timeout, False, False)
            else:
                raise NotSupportLocatorTypeErr(f"{method}：定位方式暂时不支持")

    def find_element_clickable(self, locator, isContains=False, timeout=8):
        """
        元素找到直接点击的，如果没有找到元素，直接assert False
        封装这个方法避免一些问题：ele.click()  也省略了写法: if ele is not None: ele.click()
        """

        if isinstance(locator, list):
            for lo in locator:
                method = lo[0]
                values = lo[1]

                if method == PhoneBy.ID:
                    if isinstance(values, list):
                        start_time = time.time()
                        while time.time() - start_time <= timeout:
                            for va in values:
                                if self.id_element_clickable(va, 0.1):
                                    return True
                                continue
                    else:
                        if self.id_element_clickable(values, timeout):
                            return True

                elif method == PhoneBy.XPATH:
                    if isinstance(values, list):
                        start_time = time.time()
                        while time.time() - start_time <= timeout:
                            for va in values:
                                if self.xpath_element_clickable(va, 0.1):
                                    return True
                                continue
                    else:
                        if self.xpath_element_clickable(values, timeout):
                            return True

                elif method == PhoneBy.AccessibilityId:
                    if isinstance(values, list):
                        start_time = time.time()
                        while time.time() - start_time <= timeout:
                            for va in values:
                                if self.accessibility_id_element_clickable(va, isContains, 0.1):
                                    return True
                                continue
                    else:
                        if self.accessibility_id_element_clickable(values, isContains, timeout):
                            return True

                elif method == PhoneBy.COMPOSE_CLASS_NAME_WITH_TEXT:
                    if isinstance(values, list):
                        start_time = time.time()
                        while time.time() - start_time <= timeout:
                            for va in values:
                                if self.class_name_text_element_clickable(va[0], va[1], isContains, 0.1):
                                    return True
                                continue
                    else:
                        if self.class_name_text_element_clickable(values[0], values[1], isContains, timeout):
                            return True
                elif method == PhoneBy.CLASS_NAME:
                    if isinstance(values, list):
                        start_time = time.time()
                        while time.time() - start_time <= timeout:
                            for va in values:
                                if self.class_name_element_clickable(va, 0.1):
                                    return True
                                continue
                    else:
                        if self.class_name_element_clickable(values, timeout):
                            return True

                continue
            assert False, f"列表中的元素，均点击失败"
        else:
            method = locator[0]
            values = locator[1]
            if method == PhoneBy.ID:
                if isinstance(values, list):
                    start_time = time.time()
                    while time.time() - start_time <= timeout:
                        for va in values:
                            if self.id_element_clickable(va, 0.1):
                                return True
                            continue
                    assert False, f"列表中的元素{values}，均点击失败"
                else:
                    if self.id_element_clickable(values, timeout):
                        return True
                    assert False, f"元素{values}，点击失败"

            elif method == PhoneBy.XPATH:
                if isinstance(values, list):
                    start_time = time.time()
                    while time.time() - start_time <= timeout:
                        for va in values:
                            if self.xpath_element_clickable(va, 0.1):
                                return True
                            continue
                    assert False, f"列表中的元素{values}，均点击失败"
                else:
                    if self.xpath_element_clickable(values, timeout):
                        return True
                    assert False, f"元素{values}，点击失败"

            elif method == PhoneBy.AccessibilityId:
                if isinstance(values, list):
                    start_time = time.time()
                    while time.time() - start_time <= timeout:
                        for va in values:
                            if self.accessibility_id_element_clickable(va, isContains, 0.1):
                                return True
                            continue
                    assert False, f"列表中的元素{values}，均点击失败"
                else:
                    if self.accessibility_id_element_clickable(values, isContains, timeout):
                        return True
                    assert False, f"元素{values}，点击失败"

            elif method == PhoneBy.COMPOSE_CLASS_NAME_WITH_TEXT:
                if isinstance(values, list):
                    start_time = time.time()
                    while time.time() - start_time <= timeout:
                        for va in values:
                            if self.class_name_text_element_clickable(va[0], va[1], isContains, 0.1):
                                return True
                            continue
                    assert False, f"列表中的元素{values}，均点击失败"
                else:
                    if self.class_name_text_element_clickable(values[0], values[1], isContains, timeout):
                        return True
                    assert False, f"元素{values}，点击失败"
            elif method == PhoneBy.CLASS_NAME:
                if isinstance(values, list):
                    start_time = time.time()
                    while time.time() - start_time <= timeout:
                        for va in values:
                            if self.class_name_element_clickable(va, 0.1):
                                return True
                            continue
                    assert False, f"列表中的元素{values}，均点击失败"
                else:
                    if self.class_name_element_clickable(values, timeout):
                        return True
                    assert False, f"元素{values}，点击失败"

            else:
                raise NotSupportLocatorTypeErr(f"{method}：定位方式暂时不支持")

    def find_elements(self, locator, isContains=False, timeout=8):
        """
        :param locator: 元组：(定位方法, 定位文本)，比如('xpath', '//*[@text="视频"]')
        :param isContains
        :param timeout: ios 超时
        :return:
        """
        if isinstance(locator, list):
            for lo in locator:
                method = lo[0]
                values = lo[1]
                if method == PhoneBy.ID:
                    if isinstance(values, list):
                        start_time = time.time()
                        while time.time() - start_time <= timeout:
                            for va in values:
                                eleS = self.find_element_by_id(va, 0.1, True, True)
                                if eleS is not None:
                                    return eleS
                                continue
                    else:
                        eleS = self.find_element_by_id(values, timeout, True, True)
                        if eleS is not None:
                            return eleS

                elif method == PhoneBy.XPATH:
                    if isinstance(values, list):
                        start_time = time.time()
                        while time.time() - start_time <= timeout:
                            for va in values:
                                eleS = self.find_element_by_xpath(va, 0.1, True, True)
                                if eleS is not None:
                                    return eleS
                                continue
                    else:
                        eleS = self.find_element_by_xpath(values, timeout, True, True)
                        if eleS is not None:
                            return eleS

                elif method == PhoneBy.AccessibilityId:
                    if isinstance(values, list):
                        start_time = time.time()
                        while time.time() - start_time <= timeout:
                            for va in values:
                                eleS = self.find_similar_accessibility_id(va, isContains, 0.1, True, True)
                                if eleS is not None:
                                    return eleS
                                continue
                    else:
                        eleS = self.find_similar_accessibility_id(values, isContains, timeout, True, True)
                        if eleS is not None:
                            return eleS

                elif method == PhoneBy.COMPOSE_CLASS_NAME_WITH_TEXT:
                    # class_name, text
                    if isinstance(values, list):
                        start_time = time.time()
                        while time.time() - start_time <= timeout:
                            for va in values:
                                eleS = self.find_element_by_class_name_text(va[0], va[1], isContains, 0.1, True, True)
                                if eleS is not None:
                                    return eleS
                                continue
                    else:
                        eleS = self.find_element_by_class_name_text(values[0], values[1], isContains, timeout,
                                                                    True, True)
                        if eleS is not None:
                            return eleS
                elif method == PhoneBy.CLASS_NAME:
                    if isinstance(values, list):
                        start_time = time.time()
                        while time.time() - start_time <= timeout:
                            for va in values:
                                eleS = self.find_element_by_class_name(va, 0.1, True, True)
                                if eleS is not None:
                                    return eleS
                                continue
                    else:
                        eleS = self.find_element_by_class_name(values, timeout, True, True)
                        if eleS is not None:
                            return eleS
                continue
            return None

        else:
            method = locator[0]
            values = locator[1]
            if method == PhoneBy.ID:
                if isinstance(values, list):
                    start_time = time.time()
                    while time.time() - start_time <= timeout:
                        for va in values:
                            eleS = self.find_element_by_id(va, 0.1, True, True)
                            if eleS is not None:
                                return eleS
                            continue
                    return None
                else:
                    return self.find_element_by_id(values, timeout, True, True)

            elif method == PhoneBy.XPATH:
                if isinstance(values, list):
                    start_time = time.time()
                    while time.time() - start_time <= timeout:
                        for va in values:
                            eleS = self.find_element_by_xpath(va, 0.1, True, True)
                            if eleS is not None:
                                return eleS
                            continue
                    return None
                else:
                    return self.find_element_by_xpath(values, timeout, True, True)

            elif method == PhoneBy.AccessibilityId:
                if isinstance(values, list):
                    start_time = time.time()
                    while time.time() - start_time <= timeout:
                        for va in values:
                            eleS = self.find_similar_accessibility_id(va, isContains, 0.1, True, True)
                            if eleS is not None:
                                return eleS
                            continue
                    return None
                else:
                    return self.find_similar_accessibility_id(values, isContains, timeout, True, True)

            elif method == PhoneBy.COMPOSE_CLASS_NAME_WITH_TEXT:
                # class_name, text
                if isinstance(values, list):
                    start_time = time.time()
                    while time.time() - start_time <= timeout:
                        for va in values:
                            eleS = self.find_element_by_class_name_text(va[0], va[1], isContains, 0.1, True, True)
                            if eleS is not None:
                                return eleS
                            continue
                    return None
                else:
                    return self.find_element_by_class_name_text(values[0], values[1], isContains, timeout, True, True)

            elif method == PhoneBy.CLASS_NAME:
                if isinstance(values, list):
                    start_time = time.time()
                    while time.time() - start_time <= timeout:
                        for va in values:
                            eleS = self.find_element_by_class_name(va, 0.1, True, True)
                            if eleS is not None:
                                return eleS
                            continue
                    return None
                else:
                    return self.find_element_by_class_name(values, timeout, True, True)
            else:
                raise NotSupportLocatorTypeErr(f"{method}：定位方式暂时不支持")

    def judge_element_exists(self, locator, isContains=False, timeout=8.0) -> bool:
        """
        支持多元素的 任一元素存在判对的情况
        """
        if isinstance(locator, list):
            for lo in locator:
                method = lo[0]
                values = lo[1]
                if method == PhoneBy.ID:
                    if isinstance(values, list):
                        start_time = time.time()
                        while time.time() - start_time <= timeout:
                            for va in values:
                                if self.id_element_exists(va, 1):
                                    return True
                                continue
                    else:
                        if self.id_element_exists(values, timeout):
                            return True

                elif method == PhoneBy.XPATH:
                    if isinstance(values, list):
                        start_time = time.time()
                        while time.time() - start_time <= timeout:
                            for va in values:
                                if self.xpath_element_exists(va, 1):
                                    return True
                                continue
                    else:
                        if self.xpath_element_exists(values, timeout):
                            return True

                elif method == PhoneBy.AccessibilityId:
                    if isinstance(values, list):
                        start_time = time.time()
                        while time.time() - start_time <= timeout:
                            for va in values:
                                if self.accessibility_id_element_exists(va, isContains, 1):
                                    return True
                                continue
                    else:
                        if self.accessibility_id_element_exists(values, isContains, timeout):
                            return True

                elif method == PhoneBy.COMPOSE_CLASS_NAME_WITH_TEXT:
                    """
                    (PhoneBy.COMPOSE_CLASS_NAME_WITH_TEXT, [('className1','text1'),('className2','text2')])
                    """
                    if isinstance(values, list):
                        start_time = time.time()
                        while time.time() - start_time <= timeout:
                            for va in values:
                                if self.class_name_text_element_exists(va[0], va[1], isContains, 0.1):
                                    return True
                                continue
                    else:
                        if self.class_name_text_element_exists(values[0], values[1], isContains, timeout):
                            return True

                elif method == PhoneBy.CLASS_NAME:
                    """
                    (PhoneBy.COMPOSE_CLASS_NAME_WITH_TEXT, [('className1','text1'),('className2','text2')])
                    """
                    if isinstance(values, list):
                        start_time = time.time()
                        while time.time() - start_time <= timeout:
                            for va in values:
                                if self.class_name_element_exists(va, 0.1):
                                    return True
                                continue
                    else:
                        if self.class_name_element_exists(values, timeout):
                            return True
                continue
            return False

        else:
            method = locator[0]
            values = locator[1]
            if method == PhoneBy.ID:
                if isinstance(values, list):
                    start_time = time.time()
                    while time.time() - start_time <= timeout:
                        for va in values:
                            if self.id_element_exists(va, 1):
                                return True
                            continue
                    return False
                else:
                    return self.id_element_exists(values, timeout)

            elif method == PhoneBy.XPATH:
                if isinstance(values, list):
                    start_time = time.time()
                    while time.time() - start_time <= timeout:
                        for va in values:
                            if self.xpath_element_exists(va, 1):
                                return True
                            continue
                    return False
                else:
                    return self.xpath_element_exists(values, timeout)

            elif method == PhoneBy.AccessibilityId:
                if isinstance(values, list):
                    start_time = time.time()
                    while time.time() - start_time <= timeout:
                        for va in values:
                            if self.accessibility_id_element_exists(va, isContains, 1):
                                return True
                            continue
                    return False
                else:
                    return self.accessibility_id_element_exists(values, isContains, timeout)

            elif method == PhoneBy.COMPOSE_CLASS_NAME_WITH_TEXT:
                """
                (PhoneBy.COMPOSE_CLASS_NAME_WITH_TEXT, [('className1','text1'),('className2','text2')])
                """
                if isinstance(values, list):
                    start_time = time.time()
                    while time.time() - start_time <= timeout:
                        for va in values:
                            if self.class_name_text_element_exists(va[0], va[1], isContains, 0.1):
                                return True
                            continue
                    return False
                else:
                    return self.class_name_text_element_exists(values[0], values[1], isContains, timeout)

            elif method == PhoneBy.CLASS_NAME:
                """
                (PhoneBy.COMPOSE_CLASS_NAME_WITH_TEXT, [('className1','text1'),('className2','text2')])
                """
                if isinstance(values, list):
                    start_time = time.time()
                    while time.time() - start_time <= timeout:
                        for va in values:
                            if self.class_name_element_exists(va, 0.1):
                                return True
                            continue
                    return False
                else:
                    return self.class_name_element_exists(values, timeout)

            else:
                raise NotSupportLocatorTypeErr(f"{method}：定位方式暂时不支持")

    def judge_element_not_exists(self, locator, isContains=False, timeout=8) -> bool:
        """
        不支持 多元素的不存在判断，封装后不好操作
        """
        method = locator[0]
        values = locator[1]
        if isinstance(values, list):
            assert False, "judge_element_not_exists() 方法不支持多元素"
        else:
            if method == PhoneBy.ID:
                return self.id_element_not_exists(values, timeout)

            elif method == PhoneBy.XPATH:
                return self.xpath_element_not_exists(values, timeout)

            elif method == PhoneBy.AccessibilityId:
                return self.accessibility_id_element_not_exists(values, isContains, timeout)

            elif method == PhoneBy.COMPOSE_CLASS_NAME_WITH_TEXT:
                # class_name, text
                return self.class_name_text_element_not_exists(values[0], values[1], isContains, timeout)

            elif method == PhoneBy.CLASS_NAME:
                return self.class_name_element_not_exists(values, timeout)
            else:
                raise NotSupportLocatorTypeErr(f"{method}：定位方式暂时不支持")

    @staticmethod
    def ios_ele_attribute(ios_ele):
        all_att = ["id", "className", "bounds", "text", "enabled", "checked", "displayed",
                   "label", "value", "name", "visible", "accessible", "accessibilityContainer"]

        store_ele = {}
        for ia in all_att:
            try:
                if ia == "id":
                    store_ele['id'] = ios_ele._id
                elif ia == "className":
                    store_ele['className'] = ios_ele.className
                elif ia == "bounds":
                    store_ele['bounds'] = ios_ele.bounds
                elif ia == "text":
                    store_ele['text'] = ios_ele.text
                elif ia == "enabled":
                    store_ele['enabled'] = ios_ele.enabled
                elif ia == "checked":
                    store_ele['checked'] = ios_ele.checked
                elif ia == "displayed":
                    store_ele['displayed'] = ios_ele.displayed
                elif ia == "label":
                    store_ele['label'] = ios_ele.label
                elif ia == "value":
                    store_ele['value'] = ios_ele.value
                elif ia == "name":
                    store_ele['name'] = ios_ele.name
                elif ia == "visible":
                    store_ele['visible'] = ios_ele.visible
                elif ia == "accessible":
                    store_ele['accessible'] = ios_ele.accessible
                elif ia == "accessibilityContainer":
                    store_ele['accessibilityContainer'] = ios_ele.accessibilityContainer
            except AttributeError as e:
                store_ele[ia] = ""

        return store_ele

    def get_ele_attribute(self, ele, attribute_value=None):
        """
        ele: 元素对象
        """
        if self.platform == GlobalVar.IOS:
            attribute_info = self.ios_ele_attribute(ele)
            if attribute_value is None:
                return attribute_info
            else:
                if attribute_value == "bounds":
                    x, y, w, h = attribute_info.get("bounds")
                    return x, y, x + w, y + h
                else:
                    return attribute_info.get(attribute_value)
        else:
            # print(1)
            attribute_info = ele.info
            # print(2)
            if attribute_value is None:
                return attribute_info
            else:
                if attribute_value == "bounds":
                    visibleBounds = attribute_info.get("visibleBounds")
                    # 内圈位置
                    if visibleBounds is not None:
                        get_bounds = visibleBounds
                    else:
                        get_bounds = attribute_info.get("bounds")

                    top = get_bounds.get('top')
                    bottom = get_bounds.get('bottom')
                    x1 = get_bounds.get('left')
                    x2 = get_bounds.get('right')

                    height = bottom - top
                    y1 = top
                    y2 = top + height
                    # y2 > y1
                    return x1, y1, x2, y2
                elif attribute_value == "text":
                    return attribute_info.get("text")
                elif attribute_value == "enabled":
                    return attribute_info.get("enabled")
                elif attribute_value == "checked":
                    return attribute_info.get("checked")
                elif attribute_value == "contentDescription":
                    return attribute_info.get("contentDescription")
                elif attribute_value == "clickable":
                    return attribute_info.get("clickable")
                elif attribute_value == "focusable":
                    return attribute_info.get("focusable")
                elif attribute_value == "focused":
                    return attribute_info.get("focused")

    def long_press_element(self, element, duration=3):
        """
        element: 元素对象
        长按控件
        """
        if self.platform == GlobalVar.IOS:
            element.tap_hold(duration)
        else:
            element.long_click(duration)

    def get_text(self, element):
        """
        element: 元素对象
        """
        if self.platform == GlobalVar.IOS:
            return element.text
        else:
            return element.get_text()

    def swipe_by_screen(self, direction, swipe_times=1, scale=0.5):
        """
        整个屏幕滑动
        """
        if self.platform == GlobalVar.IOS:
            if direction == "left":
                for t in range(swipe_times):
                    self.driver.swipe_left()
            elif direction == "right":
                for t in range(swipe_times):
                    self.driver.swipe_right()
            elif direction == "up":
                for t in range(swipe_times):
                    self.driver.swipe_up()
                    self.sleep_op(1.5)
            elif direction == "down":
                for t in range(swipe_times):
                    self.driver.swipe_down()
                    self.sleep_op(1.5)
        else:
            for t in range(swipe_times):
                self.driver.swipe_ext(direction, scale=scale)  # 默认0.9, 滑动距离为屏幕宽度的90%

    def swipe_by_location(self, x1, y1, x2, y2, duration=0.5):
        """
        坐标滑动
        """
        self.driver.swipe(x1, y1, x2, y2, duration=duration)

    def get_page_source(self, source_format='xml'):
        """
        获取页面源码
        """
        if self.platform == GlobalVar.IOS:
            if source_format == 'xml':
                return self.driver.source(format=source_format, accessible=False)
            else:
                return self.driver.source(accessible=True)  # default false, format JSON
        else:
            return self.driver.dump_hierarchy(compressed=True, pretty=True)

    def regular_page_data(self, xml_left: str, xml_right: str):
        """
        通过正则获取页面的内容
        """
        page_xml = self.get_page_source()
        regular_express = f'{xml_left}(.+?){xml_right}'
        find_xml_result = re.findall(regular_express, page_xml)
        return find_xml_result

    def screen_orientation(self):
        """
        获取屏幕方向，以此判断当前是竖屏还是横屏 orientation
        屏幕方向字符串（"natural"、"left"、"right"、"upsidedown"）
        """
        get_orientation = self.driver.orientation
        if get_orientation == "natural":
            # 竖屏
            print('当前是竖屏')
            return False
        else:
            # 横屏 ，left 或 right
            print('已进入横屏')
            return True

    def element_offset_lick(self, ele, gear=6):
        """
        点击控件中间无效，可以用这个方式点击右边或左边
        gear: 挡位， 1 -8 表示从左到右的分段。值越xiao 越往右偏移的多
        """
        x1, y1, x2, y2 = self.get_ele_attribute(ele, attribute_value='bounds')
        y = y1 + (y2 - y1) / 2
        x = x1 + (x2 - x1) / 2
        if self.screen_orientation():  # 当前在横屏
            add_x = x + (x2 - x1) / gear
        else:
            add_x = x
        self.tap_screen(add_x, y, percentage=False)

    @staticmethod
    def set_text(element, text):
        element.set_text(text)

    @staticmethod
    def clear_text(element):
        element.clear_text()

    def element_screenshot(self, locator=None, image_recognition=False):
        """
        对控件或全屏进行截图，返回截图文件路径
        """
        if not os.path.exists(SCREEN_SHOT_PATH):
            os.mkdir(SCREEN_SHOT_PATH)

        screen_image_name = screenshot_path(os.path.join(SCREEN_SHOT_PATH, f'{time.strftime(YMDHMS__)}.png'))
        self.driver.screenshot().save(screen_image_name)


    def allure_report_screenshot(self):
        """
        数据表里直接存图片的字节数据，
        后端处理成图片，前端再显示图片，单独接口不会影响性能

        png_data_info = self.driver.screenshot(format='raw')
        with open("生成的图片.png", "wb") as imgFile:
            imgFile.write(png_data_info)

        """
        png_data_info = self.driver.screenshot(format='raw')
        return png_data_info

    def double_click(self, x, y):
        """
        双击坐标 安卓
        :param x: x坐标
        :param y: y坐标
        """
        if self.platform == GlobalVar.IOS:
            pass
        else:
            self.driver.double_click(x, y)

    def wait_activity(self, activity, timeout=10):
        """
        等待指定Activity出现
        :param activity: Activity名称
        :param timeout: 超时时间
        """
        if self.platform == GlobalVar.IOS:
            pass
        else:
            self.driver.wait_activity(activity, timeout)

    def set_fastInput_ime(self):
        """
        设置FastInputIME输入法
        """
        if self.platform == GlobalVar.IOS:
            pass
        self.driver.set_fastinput_ime(True)

    def set_original_ime(self):
        """
        设置原始输入法
        """
        if self.platform == GlobalVar.IOS:
            pass
        self.driver.set_fastinput_ime(False)

    def close_ime(self, watch_ime=3):
        """
        关闭输入法
        """
        start_check = time.time()
        while time.time() - start_check < watch_ime:
            exist_ime_handle = self.find_element((PhoneBy.ID, ['Done', 'Search']), timeout=0.5)
            if exist_ime_handle is not None:
                exist_ime_handle.click()
                break
            continue

    def input_text(self, ele, text=None, timeout=2):
        """
        输入文本
        text: 要输入的文本
        """
        if self.platform == GlobalVar.IOS:
            input_ele = self.find_element(ele, timeout=timeout)
            input_ele.click()
            input_ele.clear_text()
            self.driver.send_keys(text)
            self.sleep_op(0.2)
            # 需要关闭一下，因为ios目前跑的情况，没有自动关闭。
            self.close_ime()
        else:
            self.find_element_clickable(ele, timeout=timeout)
            self.driver.clear_text()
            self.driver.send_keys(text)

    def press_action(self, keyId):
        """
        模拟按键
        """
        if self.platform == GlobalVar.IOS:
            keys = {
                3: "power",  # 电源键
                4: "volumeUp",  # 音量上键
                5: "volumeDown",  # 音量下键
            }
            if keyId == 1:
                self.tap_screen(0.063, 0.08)
            else:
                self.driver.press(keys[keyId])
        else:
            android_keys = {
                1: "back",  # 返回键
                2: "home",  # Home键
                3: "power",  # 电源键
                4: "volume_up",  # 音量上键
                5: "volume_down",  # 音量下键
                6: "menu",  # 菜单键
                7: "recent",  # 最近任务键

            }
            self.driver.press(android_keys[keyId])

    def set_orientation(self, orientation):
        """
        设置屏幕方向
        :param orientation: 屏幕方向字符串（"natural"、"left"、"right"、"upsidedown"）
        """
        if self.platform == GlobalVar.IOS:
            pass
        else:
            self.driver.set_orientation(orientation)

    def open_notification(self):
        """
        打开通知栏
        """
        if self.platform == GlobalVar.IOS:
            pass
        else:
            self.driver.open_notification()

    def close_notification(self):
        """
        关闭通知栏
        """
        if self.platform == GlobalVar.IOS:
            pass
        else:
            self.driver.close_notification()

    def open_quick_settings(self):
        """
        打开快速设置
        """
        if self.platform == GlobalVar.IOS:
            pass
        else:
            self.driver.open_quick_settings()

    def close_quick_settings(self):
        """
        关闭快速设置
        """
        if self.platform == GlobalVar.IOS:
            pass
        else:
            self.driver.close_quick_settings()

    def install_app(self, apk_path):
        """
        安装应用
        :param apk_path: APK文件路径
        """
        if self.platform == GlobalVar.IOS:
            pass
        else:
            self.driver.app_install(apk_path)

    def uninstall_app(self, package_name):
        """
        卸载应用
        :param package_name: 包名
        """
        if self.platform == GlobalVar.IOS:
            pass
        else:
            self.driver.app_uninstall(package_name)

    def get_app_info(self, package_name, file_path_=None, case_executor=None, isWrite=True):
        """
        获取应用信息
        :param package_name: 包名
        :param file_path_: 保存路径
        :param case_executor: 执行者
        :param isWrite: 是否写入文件
        :return: 应用信息字典
        """
        if isWrite:
            save_info_path = os.path.join(file_path_, "app_info.txt")

            with open(save_info_path, 'w', encoding='utf8') as ai:
                ai.write(f"{case_executor}\n")
                if self.platform == GlobalVar.IOS:
                    try:
                        ios_app_info = subprocess.check_output(f'tidevice appinfo {package_name}', shell=True,
                                                               encoding='gbk')
                    except Exception as u:
                        ios_app_info = subprocess.check_output(f'tidevice appinfo {package_name}', shell=True,
                                                               encoding='utf8')
                    app_name = re.findall("'CFBundleName': '(.+?)',", ios_app_info)
                    app_version = re.findall("'CFBundleShortVersionString': '(.+?)',", ios_app_info)

                    final_app_name = app_name[0] if len(app_name) != 0 else ""
                    final_app_version = app_version[0] if len(app_version) != 0 else ""
                    new_ios_app_info = {'packageName': package_name,
                                        'label': final_app_name,
                                        'versionName': final_app_version}
                    ai.write(str(new_ios_app_info))
                    return final_app_name, final_app_version
                else:
                    android_app_info = self.driver.app_info(package_name)
                    app_name = android_app_info.get("label")
                    app_version = android_app_info.get("versionName")
                    ai.write(str(android_app_info))
                    return app_name, app_version
        else:
            if self.platform == GlobalVar.IOS:
                try:
                    ios_app_info = subprocess.check_output(f'tidevice appinfo {package_name}', shell=True,
                                                           encoding='gbk')
                except Exception as u:
                    ios_app_info = subprocess.check_output(f'tidevice appinfo {package_name}', shell=True,
                                                           encoding='utf8')
                app_name = re.findall("'CFBundleName': '(.+?)',", ios_app_info)
                app_version = re.findall("'CFBundleShortVersionString': '(.+?)',", ios_app_info)

                final_app_name = app_name[0] if len(app_name) != 0 else ""
                final_app_version = app_version[0] if len(app_version) != 0 else ""
                return final_app_name, final_app_version
            else:
                android_app_info = self.driver.app_info(package_name)
                app_name = android_app_info.get("label")
                app_version = android_app_info.get("versionName")
                return app_name, app_version

    def get_current_package_name(self):
        """
        获取当前应用包名
        :return: 包名字符串
        """
        if self.platform == GlobalVar.IOS:
            pass
        else:
            return self.driver.current_package()

    def get_current_activity(self):
        """
        获取当前Activity名称
        :return: Activity名称字符串
        """
        if self.platform == GlobalVar.IOS:
            pass
        else:
            return self.driver.current_activity()

    def get_toast_message(self, toast_info: list, wait_time=10):
        """
        获取toast 内容
        """
        if self.platform == GlobalVar.IOS:
            toa_time = time.time()
            while time.time() - toa_time <= 8:
                if self.judge_element_exists((PhoneBy.AccessibilityId, toast_info), isContains=True, timeout=0.5):
                    print("已获取到toast")
                    return True
                continue
            assert False, f"这些toast {toast_info} 都没有匹配到"
        else:
            toa_time = time.time()
            while time.time() - toa_time <= wait_time:
                xml_toast = self.get_page_source()
                find_xml_toast = [xt for xt in toast_info if xt in xml_toast]
                if find_xml_toast:
                    print("已获取到非toast结果")
                    return True
                message = self.driver.toast.get_message(wait_timeout=3, cache_timeout=3)
                if message is not None:
                    find_toast = [mt for mt in toast_info if mt in message]
                    if find_toast:
                        print("已获取到toast")
                        self.driver.toast.reset()
                        return True
                    continue

            assert False, f"这些toast {toast_info} 都没有匹配到"

    def start_screenrecord(self, screenrecord_path):
        """
        需安装依赖  pip3 install -U "uiautomator2[image]"
        开始录屏
        """
        if self.platform == GlobalVar.IOS:
            pass
        else:
            self.driver.screenrecord(screenrecord_path)

    def stop_screenrecord(self):
        """
        结束录屏
        """
        if self.platform == GlobalVar.IOS:
            pass
        else:
            time.sleep(2)
            self.driver.screenrecord.stop()

    def element_bounds_exist(self, loc_text: str | list, index=0, timeout=8.0) -> bool:
        """
        loc_text  定位字符串内容
        """
        if isinstance(loc_text, str):
            exist_start = time.time()
            while time.time() - exist_start <= timeout:
                _page_xml = self.get_page_source()
                judge_x, judge_y = self.get_element_pos_from_xml(_page_xml, loc_text, index)
                if judge_x is not None:
                    return True
            return False

        else:
            exist_start = time.time()
            while time.time() - exist_start <= timeout:
                _page_xml = self.get_page_source()
                for lt in loc_text:
                    judge_x, judge_y = self.get_element_pos_from_xml(_page_xml, lt, index)
                    if judge_x is not None:
                        return True
            return False

    def get_element_pos_from_xml(self, str_xml, text, index=0) -> tuple:
        """
        找到所有的结果
        android 是  bounds
        ios 是 x="28" y="142" width="24" height="25"

        """
        if self.platform == GlobalVar.IOS:
            save_find_index = []
            keywords_str = text
            pattern = re.compile(keywords_str)
            search_result = pattern.search(str_xml)
            while search_result:
                # print(f"<{search_result.group()}>位置：{search_result.start()}")
                save_find_index.append(search_result.start())
                search_result = pattern.search(str_xml, search_result.start() + 1)

            if save_find_index:
                str_end = str_xml[save_find_index[index]:]
                pos1 = str_end.find('x="')
                if pos1 > -1:
                    str_end = str_end[pos1:]
                    pos2 = str_end.find('" index="')
                    str_bound = str_end[0:pos2]
                    str_pos_arr = str_bound.split('"')
                    x1 = int(str_pos_arr[1])
                    y1 = int(str_pos_arr[3])
                    w = int(str_pos_arr[5])
                    h = int(str_pos_arr[7])

                    x2 = x1 + w
                    y2 = y1 + h

                    pos_x = x1 + (x2 - x1) / 2
                    pos_y = y1 + (y2 - y1) / 2
                    return pos_x, pos_y
            return None, None

        else:
            save_find_index = []
            keywords_str = text
            pattern = re.compile(keywords_str)
            search_result = pattern.search(str_xml)
            while search_result:
                # print(f"<{search_result.group()}>位置：{search_result.start()}")
                save_find_index.append(search_result.start())
                search_result = pattern.search(str_xml, search_result.start() + 1)

            if save_find_index:
                str_end = str_xml[save_find_index[index]:]
                pos1 = str_end.find('bounds="[')
                if pos1 > -1:
                    str_end = str_end[pos1 + 9:]
                    pos2 = str_end.find(']"')
                    str_bound = str_end[0:pos2]
                    str_bound = str_bound.replace('][', ',')
                    str_pos_arr = str_bound.split(',')
                    pos_x = int(str_pos_arr[0]) + int((int(str_pos_arr[2]) - int(str_pos_arr[0])) / 2)
                    pos_y = int(str_pos_arr[1]) + int((int(str_pos_arr[3]) - int(str_pos_arr[1])) / 2)

                    return pos_x, pos_y
            return None, None

    def click_screen_center(self):
        """
        点击手机屏幕中间
        """
        self.tap_screen(0.5, 0.5)
        print("点击了屏幕")